#ifndef SCHEDULER_H
#define SCHEDULER_H

#include "initialize.h"

#define INIT 0
#define READY 1 //表示这个stage已经完成了所有父任务，随时可以开始执行了
#define RUNNING 2
#define FINISH 3

#define RECSSD 2
#define TEXT 3
#define IMAGE 4
#define LAST_NDP 5 //标记NDP种类的末尾，便于判断

#define PARENT 0
#define CHILD 1

#define READY_LIST 0
#define RUNNING_LIST 1

struct scheduler{
    unsigned int task_count; //记录实时任务数
    unsigned int total_task_count; //记录总任务数，只增不减
    struct task* task_head;
    struct task* task_tail;

    struct stage** chip_stage_list_head; //指针数组，大小为channel数*chip数。每个元素是一个stage指针，指向这个单元的待执行stage
    struct stage* recssd_stage_list_head; //每个单元一个
    struct stage* image_stage_list_head;
    struct stage* text_stage_list_head;

    struct ssd_info* ssd; //将ssd结构连接到里面来
};

struct task{
    int task_id;
    int task_ope; //任务类型，按照ssdsim的标准来，0写 1读 2text 3image 4recssd
    int total_stage; //不是标识当前剩余stage的，只增不减。删除的时候也不-1
    int total_finished_stage; //完成了的stage(目前没用)
    int task_status; //状态
    unsigned long finish_time; //主要用于记录NDP任务的完成时间

    //struct stage* first_stage; //指向第一个stage
    struct task* next_task; //把所有task链起来，便于scheduler遍历

    struct stage* stage_queue_head; //把所有的stage按序链接起来，便于遍历和delete
    struct stage* stage_queue_tail;

    struct stage* ready_stage_head; //当前阶段所有可执行的stage(父阶段已经完成了的，保存起来避免遍历所有stage)
    struct stage* running_stage_head;

    struct request* request;
};

struct stage_dep{ //用于标记一个stage的父stage和子stage
    short id; //标记依赖的id
    short status; //标记这个依赖的状态
    struct stage_dep* next; //链接起下一个依赖
    struct stage* stage;
};

struct stage{
    int id;
    int ope; //阶段的操作类型，按照ssdsim的标准来，0写 1读 2text 3image 4recssd
    int lpn; //这个stage要读取的逻辑页
    int channel;
    int chip; //这个stage需要操作的chip和channel。-1表示无需操作
    int dispatched; //标记是否已经完成读取，0表示没有，1表示已读取
    int status; //状态，0等待，1正在运行，2完成
    struct task* task; //记录所属的任务，用于完成阶段后的标记

    //标记分发时间和完成时间
    unsigned long start_time;
    unsigned long finish_time;

    //标记预计运行时间用于调度
    int predict_time;

    //标记一共有多少个父任务以及完成了多少父任务，用于快速查询是否可执行
    int total_parent_stage;
    int finished_parent_stage;
    
    int CPD; //这个阶段的关键度
    
    //用链表的方式存储所有的父阶段和子阶段
    struct stage_dep* child_stage_head; //指向子阶段链表的头
    struct stage_dep* parent_stage_head; //指向子阶段链表的头

    //用于把同一任务中的stage链接起来，用于遍历和delete的时候用
    struct stage* next_stage_of_task;

    //指向同一执行单元的下一个任务
    struct stage* next_stage_of_unit; //指向同一单元请求队列的下一个任务，用于功能单元执行任务
    struct stage* prev_stage_of_unit;

    //指向同一个任务中下一个可执行的stage
    struct stage* next_stage_of_status; //用于指向同一运行状态的下一个stage(ready_stage_head or running_stage_head)
    struct stage* prev_stage_of_status;

    struct acc_unit_info* acc_unit; //指向该stage所占用的加速器单元，用于释放资源用

    struct sub_request* sub_request; //与ssdsim的sub_request相连接，便于修改状态及分发任务
};

int append_stage(struct stage* parent_stage, struct stage* child_stage); //将第二个stage添加到第一个stage后作为子阶段
int append_task(struct scheduler* scheduler, struct task* task);
int init_task(struct task* task);
struct stage* init_stage();
void init_scheduler(struct ssd_info* ssd);
int exchange_stage(struct stage* a, struct stage* b);

void delete_task(struct task* task);

void print_task(struct task* task, char* prefix);

struct stage* get_stage(int stage_id, struct task* task); //获取这个task下id为stage_id的阶段

void link_stage_to_task(struct task* task, struct stage* stage);

void add_parent_stage(struct stage* child_stage, struct stage* parent_stage);

int dispatch(struct scheduler* scheduler);
int dispatch_CPCU(struct scheduler* scheduler);

void remove_from_list(struct stage* stage, struct stage** list_head);
void insert_to_list(struct stage* stage, struct stage** list_head);

#endif